/*
 * CommunicationVendedor.cpp
 *
 */

#include "../capa_servicios_distribuidos/QueueLauncher.h"
#include "../IPC/ProcessAux.h"
#include "CommunicationVendedor.h"
#include "../logger/logger.h"

namespace middleware {

const std::string CommunicationVendedor::REQUEST_QUEUE_PATH = "/tmp/vendedor";
const std::string CommunicationVendedor::REPLY_QUEUE_PATH  = "/tmp/vendedor";
const std::string CommunicationVendedor::AVAILABLE_QUEUE_PATH  = "/tmp/vendedor";
const std::string CommunicationVendedor::VENDEDORID_SEQUENCE_PATH = "/tmp/vendedor";
const std::string CommunicationVendedor::OC_ID_SEQUENCE_PATH = "/tmp/vendedor";

const char CommunicationVendedor::REQUEST_QUEUE_KEY_CLI_SIDE;
const char CommunicationVendedor::REPLY_QUEUE_KEY_CLI_SIDE;
const char CommunicationVendedor::AVAILABLE_QUEUE_KEY_CLI_SIDE;

const char CommunicationVendedor::REQUEST_QUEUE_KEY_VEND_SIDE;
const char CommunicationVendedor::REPLY_QUEUE_KEY_VEND_SIDE;
const char CommunicationVendedor::AVAILABLE_QUEUE_KEY_VEND_SIDE;

const Uid CommunicationVendedor::UIDVendedorReply = "vendedorReply";
const Uid CommunicationVendedor::UIDVendedorRequest = "vendedorRequest";
const Uid CommunicationVendedor::UIDVendedorAvailable = "vendedorAvailable";
const Uid CommunicationVendedor::UIDVendedorIdGenerator = "vendedorIdGenerator";
const Uid CommunicationVendedor::UIDOcGenerator = "ocGenerator";

CommunicationVendedor::CommunicationVendedor(std::string hostName)
	:m_RequestQueue(ipc::MessageQueue<VendedorRequestStruct>::
			get(IPCUids::getFile(UIDVendedorRequest)+hostName,IPCUids::getKey(UIDVendedorRequest))),
	 m_ReplyQueue(ipc::MessageQueue<VendedorReplyStruct>::
			get(IPCUids::getFile(UIDVendedorReply)+hostName,IPCUids::getKey(UIDVendedorReply))),
	 m_AvailableVendedor(ipc::MessageQueue<AvailableVendedorStruct>::
			get(IPCUids::getFile(UIDVendedorAvailable)+hostName,IPCUids::getKey(UIDVendedorAvailable))),
	 m_ordenCompraIdGenerator(ipc::Sequence::get(IPCUids::getFile(UIDOcGenerator)+hostName,IPCUids::getKey(UIDOcGenerator))),
	 m_HostName(hostName)
{
	m_mTypePedidoVendedorLibre = channel::AgentAddressService::registerNameStatic("vendedores_libres_service_req");
	m_mTypeInformarVendedorLibre = channel::AgentAddressService::registerNameStatic("informar_vendedores_libres_service");

}

CommunicationVendedor::~CommunicationVendedor()
{
}

int CommunicationVendedor::generateVendedorId()
{
	int vendedorId = channel::AgentAddressService::getAddress();

	servicios_distribuidos::QueueLauncher::createDynamicDistributedQueueByUid
	<VendedorRequestStruct>
	(UIDVendedorRequest,m_HostName,
	servicios_distribuidos::QUEUE_RECV,vendedorId);

	return vendedorId;
}


void CommunicationVendedor::avisarVendedorDisponible(int vendedorId)
{
	AvailableVendedorStruct message;

	message.vendedorId = vendedorId;

	m_AvailableVendedor.put(m_mTypeInformarVendedorLibre,message);
}

int CommunicationVendedor::getVendedorId(const int clientId)
{
	int vendedorId= channel::AgentAddressService::getAddress();
	AvailableVendedorStruct vendedorRequest;
	VendedorReplyStruct reply;

	vendedorRequest.clientId = clientId;

	m_AvailableVendedor.put(m_mTypePedidoVendedorLibre, vendedorRequest);

	reply = m_ReplyQueue.get(clientId);

	vendedorId = reply.vendedorId;

	return vendedorId;
}

int CommunicationVendedor::sendOrdenCompra(OrdenCompra &ordenCompra)
{
	bool retVal = false;
	ProductoCantidadList::iterator it;
	VendedorReplyStruct vendedorReply;
	VendedorRequestStruct vendedorFinalRequest;

	for(it=ordenCompra.productos.begin(); it != ordenCompra.productos.end(); it++)
	{
		VendedorRequestStruct vendedorRequest;
		vendedorRequest.requestType = ITEM_ORDEN_COMPRA;
		vendedorRequest.producto= *it;
		vendedorRequest.ordenCompra = ordenCompra.header;

		m_RequestQueue.put(ordenCompra.header.vendedorId,vendedorRequest);
		CLogger::log("Pedido de producto enviado", LogLevelEnum::TRACE);
	}

	vendedorFinalRequest.requestType = FIN_ORDEN_COMPRA;
	vendedorFinalRequest.ordenCompra = ordenCompra.header;
	m_RequestQueue.put(ordenCompra.header.vendedorId,vendedorFinalRequest);

	CLogger::log("Fin orden de compra", LogLevelEnum::TRACE);

	vendedorReply = m_ReplyQueue.get(ordenCompra.header.clientId);

	if(vendedorReply.status == OC_OK)
		retVal = true;

	return retVal;
}

void CommunicationVendedor::receiveOrdenCompra(int vendedorId,int &clientId,
													 ProductoCantidad &producto,
													 OrdenCompraHeader &ordenCompra,
													 bool &ordenCompraEnded)
{
	VendedorRequestStruct vendedorRequest;

	vendedorRequest = m_RequestQueue.get(vendedorId);
	clientId = vendedorRequest.ordenCompra.clientId;
	ordenCompra = vendedorRequest.ordenCompra;

	if(vendedorRequest.requestType == ITEM_ORDEN_COMPRA)
	{
		producto = vendedorRequest.producto;
		CLogger::log("Se recibio pedido de un item", LogLevelEnum::TRACE);
		ordenCompraEnded=false;
	}
	else
	{
		if(vendedorRequest.requestType == FIN_ORDEN_COMPRA)
		{
			producto.cantidad =0;
			producto.tipo =0;
			ordenCompraEnded = true;

			CLogger::log("Se recibio fin de pedido", LogLevelEnum::TRACE);
		}
		else
			throw Exception("Wrong request type received");
	}
}

void CommunicationVendedor::respondOrdenCompra(int clientId,OrdenCompraStatus status)
{
	VendedorReplyStruct vendedorReply;
	vendedorReply.status = status;

	m_ReplyQueue.put(clientId,vendedorReply);
}

int CommunicationVendedor::generateOrdenCompraId()
{
	return m_ordenCompraIdGenerator.getNext();
}

void CommunicationVendedor::create(VendedorCommunicationType type, std::string hostName)
{

	if(type!=VENDEDOR)
	{
		servicios_distribuidos::QueueLauncher::createDynamicDistributedQueueByUid
		<VendedorRequestStruct>
		(UIDVendedorRequest,hostName,servicios_distribuidos::QUEUE_SEND);
	}
	else
		ipc::MessageQueue<VendedorRequestStruct>::create(IPCUids::getFile(UIDVendedorRequest)+hostName,IPCUids::getKey(UIDVendedorRequest));

	if(type != CLIENTE)
	{
		servicios_distribuidos::QueueLauncher::createDynamicDistributedQueueByUid
		<VendedorReplyStruct>
			(UIDVendedorReply,hostName,servicios_distribuidos::QUEUE_SEND);
	}
	else
		ipc::MessageQueue<VendedorReplyStruct>::
		create(IPCUids::getFile(UIDVendedorReply)+hostName,IPCUids::getKey(UIDVendedorReply));


	servicios_distribuidos::QueueLauncher::createDistributedQueueByUid
		<AvailableVendedorStruct>
			(UIDVendedorAvailable,hostName,servicios_distribuidos::QUEUE_SEND);

	ipc::Sequence::create(IPCUids::getFile(UIDOcGenerator)+hostName,IPCUids::getKey(UIDOcGenerator));
}

void CommunicationVendedor::launchForClient(std::string hostName, int clientId)
{
	servicios_distribuidos::QueueLauncher::createDynamicDistributedQueueByUid
	<VendedorReplyStruct>
	(UIDVendedorReply,hostName,servicios_distribuidos::QUEUE_RECV,clientId);
}

void CommunicationVendedor::destroy(VendedorCommunicationType type,std::string hostName)
{
	ipc::MessageQueue<VendedorRequestStruct>::
				destroy(IPCUids::getFile(UIDVendedorRequest)+hostName,IPCUids::getKey(UIDVendedorRequest));
	ipc::MessageQueue<VendedorReplyStruct>::
				destroy(IPCUids::getFile(UIDVendedorReply)+hostName,IPCUids::getKey(UIDVendedorReply));
	ipc::MessageQueue<AvailableVendedorStruct>::
				destroy(IPCUids::getFile(UIDVendedorAvailable)+hostName,IPCUids::getKey(UIDVendedorAvailable));
	ipc::Sequence::destroy(IPCUids::getFile(UIDOcGenerator)+hostName,IPCUids::getKey(UIDOcGenerator));
}

} /* namespace middleware */

